#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifdef _WIN32
#include <WinSock2.h>
#include <Windows.h>
#else
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif//_WIN32

#ifndef _WIN32
typedef int SOCKET;
#define INVALID_SOCKET      (-1)
#define SOCKET_ERROR        (-1)
#define CLOSE_SOCK(sk)      close((sk))
#define LAST_ERROR()        errno
#else
#define CLOSE_SOCK(sk)      closesocket((sk))
#define LAST_ERROR()        WSAGetLastError()
typedef int socklen_t;
#endif//_WIN32

#define DEF_LISTEN_PORT 43010

static int str2int(const char *str, unsigned int *pValue)
{
	unsigned int value;
	char *pEnd;

	value = strtoul(str, &pEnd, 10);
	if(NULL == pEnd || '\0' != *pEnd)
	{
		return EINVAL;
	}
	*pValue = value;
	return 0;
}

static int InitSocket(void)
{
#ifdef _WIN32
    WSADATA wd;

    return WSAStartup(MAKEWORD(2, 2), &wd);
#else
    return 0;
#endif//_WIN32
}

static void UnInitSocket(void)
{
#ifdef _WIN32
    WSACleanup();
#endif//_WIN32
}

static int InnerRunServer(unsigned short port)
{
    int ret;
    SOCKET srvSock;
    SOCKET cliSock;
    struct sockaddr_in srvAddr = {0};
    struct sockaddr_in cliAddr = {0};
    socklen_t cliLen = sizeof(struct sockaddr_in);
    char buffer[1024] = {0};
#ifdef _WIN32
    int len;
#else
    ssize_t len;
#endif//_WIN32

    srvSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(INVALID_SOCKET == srvSock)
    {
        ret = errno;
        printf("socket for listen port failed!ret=%d\n", ret);
        return ret;
    }
	srvAddr.sin_family = AF_INET;
	srvAddr.sin_port = htons(port);
	srvAddr.sin_addr.s_addr = INADDR_ANY;
    
    int opt = 1;

    setsockopt(srvSock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
    if(SOCKET_ERROR == bind(srvSock, (struct sockaddr *)&srvAddr, sizeof(struct sockaddr_in)))
    {
        ret = errno;
        printf("bind for listen port failed!ret=%d\n", ret);
        CLOSE_SOCK(srvSock);
        return ret;
    }
    if(SOCKET_ERROR == listen(srvSock, 5))
    {
        ret = errno;
        printf("listen for listen port failed!ret=%d\n", ret);
        CLOSE_SOCK(srvSock);
        return ret;
    }
    while(true)
    {
        printf("Wait for client...\n");
        cliSock = accept(srvSock, (struct sockaddr *)&cliAddr, &cliLen);
        if(INVALID_SOCKET == cliSock)
        {
            ret = errno;
            printf("accept for listen port failed!ret=%d\n", ret);
            break;
        }
        printf("client[%s:%u] has connected!\n", inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
_RETRY:
        buffer[0] = '\0';
        len = recv(cliSock, buffer, sizeof(buffer), 0);
        if(SOCKET_ERROR == (int)len)
        {
            ret = errno;
            if(EAGAIN == ret || EWOULDBLOCK == ret)
            {
                goto _RETRY;
            }
            printf("recv for listen port failed!ret=%d\n", ret);
            CLOSE_SOCK(cliSock);
            continue;
        }
        else if(len > 0)
        {
            printf("recieve message:%s\n", buffer);
            send(cliSock, "server replay", sizeof("server replay"), 0);
            goto _RETRY;
        }
        else
        {
            printf("client disconnected!\n");
        }
    }
    CLOSE_SOCK(srvSock);
    return ret;
}

int main(int argc, char **argv)
{
    int ret;
    unsigned int port = DEF_LISTEN_PORT;

	if(argc > 1)
	{
		ret = str2int(argv[1], &port);
		if(0 != ret)
		{
			printf("Invalid port : %s", argv[2]);
			return ret;
		}
		else if (port == 0 || port > 65535)
		{
			printf("Invalid port : %s", argv[2]);
			return EINVAL;
		}
	}
    ret = InitSocket();
    if(0 != ret)
    {
        printf("InitSocket failed!ret=%d\n", ret);
        return ret;
    }
    InnerRunServer(port);
    UnInitSocket();
    return 0;
}
